<template>
  <div id="HelloWorld">
    <div id="main">
      <div id="diagramContainer">
      </div>
    </div>
    <div id="operPlan">
      <button @click="saveData">保存数据</button>
      <button @click="loadData">读取数据</button>
      <button v-if="activeDragger" @click="switchState">连线</button>
      <button v-else @click="switchState">移动</button>
    </div>
  </div>
</template>

<script>
  import jsplumb from 'jsplumb';

  export default {
    name: 'demo2',
    data() {
      return {
        jsPlumb: null,
        UUID: require('uuid'),
        topologyNode: {
          nodes: [
            {
            "id": "node1",
            "left": 175,
            "top": 61,
            "text": "节点1",
            "classList": ["node", "radius", "jtk-endpoint-anchor", "jtk-managed", "jtk-draggable", "jtk-connected", "jtk-dragged"]
          }, {
            "id": "node2",
            "left": 331,
            "top": 197,
            "text": "节点2",
            "classList": ["node", "jtk-endpoint-anchor", "jtk-managed", "jtk-draggable", "jtk-connected", "jtk-dragged"]
          }, {
            "id": "node3",
            "left": 527,
            "top": 60,
            "text": "节点3",
            "classList": ["node", "jtk-endpoint-anchor", "jtk-managed", "jtk-draggable", "jtk-connected", "jtk-dragged"]
          }]
        },
        activeDragger: true,  //是否为拖拽状态,false时节点不可拖拽移动，但可以进行节点之间连线；true时相反
      }
    },
    methods: {
      /**
       * 保存图形数据
       */
      saveData() {
        //节点信息
        const nodesInfo = this.jsPlumb.getManagedElements(), ledgeInfo = this.jsPlumb.getAllConnections(), nodes = [],
          ledges = [];
        let temp;
        for (let item in nodesInfo) {
          if (nodesInfo.hasOwnProperty(item)) {
            temp = nodesInfo[item];
            nodes.push({
              id: $(nodesInfo[item].el).attr('id'),
              left: parseInt(temp.info.o.left),
              top: parseInt(temp.info.o.top),
              text: temp.el.innerText,
              anchors: this.jsPlumb.getEndpoints(temp.el).map(i => {
                return i.getUuid()
              }),
              classList: temp.el.className.split(" "),
            })
          }
        }
        //边信息
        for (let item in ledgeInfo) {
          if (ledgeInfo.hasOwnProperty(item)) {
            temp = ledgeInfo[item];
            ledges.push({
              source: {id: temp.sourceId, uuid: temp.endpoints[0].getUuid()},
              target: {id: temp.targetId, uuid: temp.endpoints[1].getUuid()}
            });
          }
        }
        const datas = {
          nodes: nodes,
          ledges: ledges
        };
        //datas为图形数据，在http请求中将datas直接作为传输数据对
        console.log(JSON.stringify(datas))
      },
      /**
       * 装载数据，渲染图形
       * @param data string类型，是json对应的字符串
       */
      loadData(data) {
        data.nodes.forEach(item => {
          this.addNode(item);
        });
      },
      /**
       * 添加节点
       * @param node json对象，包含了id、left、top、classList、text
       */
      addNode(node) {
        $('#diagramContainer').append('<div class="' + node.classList.join(" ") + '" id="' + node.id + '" >' + node.text + '</div>');
        $("#" + node.id).css("left", node.left).css("top", node.top);
      },
      /**
       * 允许节点拖拽且网格对齐
       */
      draggable() {
        this.topologyNode.nodes.forEach(item=>{
          this.jsPlumb.draggable(item.id, {
            containment: 'parent',
            grid: [10, 10]
          })
        })
      },
      /**
       * 移除节点的可拖拽效果
       */
      removeDraggable() {
        this.topologyNode.nodes.forEach(item=>{
          this.jsPlumb.destroyDraggable(item.id);
        })
      },
      /**
       * 允许节点可绘制连线
       */
      drawLine() {
        this.topologyNode.nodes.forEach(item=>{
          this.jsPlumb.makeSource(item.id, {
            anchor: "Continuous",
          });
          this.jsPlumb.makeTarget(item.id, {
            anchor: "Continuous",
            // allowLoopback: false, //避免回环
            // deleteEndpointsOnDetach: false,  //删除连线，不删除节点
          });
        });
      },
      /**
       * 移除所有节点的可绘制连线
       */
      removeDrawLine() {
        this.jsPlumb.unmakeEverySource();
        this.jsPlumb.unmakeEveryTarget();
      },

      /**
       * 连接两个节点
       * @param id1 节点一ID
       * @param id2 节点二ID
       */
      connectNode(id1, id2) {
        this.jsPlumb.connect({
          source: id1,
          target: id2
        })
      },
      /**
       * 切换状态（移动/连线）
       */
      switchState() {
        this.activeDragger=!this.activeDragger;
        if(this.activeDragger){
          this.draggable();
          this.removeDrawLine();
        }else{
          this.removeDraggable();
          this.drawLine();
        }
      },
      /**
       * 初始化网络拓扑图
       */
      initTopology(){
        // https://blog.csdn.net/yczz/article/details/71159370 参考URL
        const jsPlumb = jsplumb.jsPlumb;
        this.jsPlumb = jsPlumb;
        const _this = this;
        jsPlumb.ready(function () {
          //节点只能在固定该区域内移动。
          jsPlumb.setContainer('diagramContainer');
          //一般来说拖动创建的链接，可以再次拖动，让链接断开。如果不想触发这种行为，可以设置。
          jsPlumb.importDefaults({
            ConnectionsDetachable: false, //连接是否可以使用鼠标
            Connector: 'Straight',  //连接线线性
            EndpointStyle: {radius: 0.01},  //端点的css样式声明
            PaintStyle: {stroke: 'black',strokeWidth: 2},  ////线的样式
            HoverPaintStyle: {stroke: 'red',cursor:'pointer'},  ////鼠标经过线的样式
          });

          jsPlumb.bind('click', function (conn) {
            if (window.prompt('确定删除所点击的链接吗？ 输入1确定') === '1') {
              jsPlumb.deleteConnection(conn)
            }
          });

          //模拟通过网络请求装载数据，渲染图形
          setTimeout(function () {
            _this.loadData(_this.topologyNode);
            _this.draggable();
          }, 1000);
        });
      }
    },
    mounted() {
      this.initTopology();
    }
  }
</script>

<style>
  #HelloWorld {
    position: relative;
  }

  #main {
    width: 60%;
    height: 400px;
    position: absolute;
  }

  #operPlan {
    right: 0;
    width: 19%;
    height: 400px;
    border: 1px solid gray;
    position: absolute;
  }

  #diagramContainer {
    position: relative;
    float: left;
    width: 100%;
    height: 100%;
    border: 1px solid gray;
    background-repeat: repeat;
  }

  .node {
    box-shadow: 2px 2px 19px #aaa;
    -o-box-shadow: 2px 2px 19px #aaa;
    -webkit-box-shadow: 2px 2px 19px #aaa;
    -moz-box-shadow: 2px 2px 19px #aaa;
    -moz-border-radius: 0.5em;
    border-radius: 0.5em;
    opacity: 0.8;
    filter: alpha(opacity=80);
    border: 1px solid #346789;
    width: 60px;
    text-align: center;
    z-index: 20;
    position: absolute;
    background-color: #eeeeef;
    color: black;
    padding: 10px;
    font-size: 9pt;
    cursor: pointer;
    height: 30px;
    line-height: 30px;
  }

  .radius {
    border-radius: 25em;
  }

  .node:hover {
    box-shadow: 2px 2px 19px #444;
    -o-box-shadow: 2px 2px 19px #444;
    -webkit-box-shadow: 2px 2px 19px #444;
    -moz-box-shadow: 2px 2px 19px #444;
    opacity: 0.8;
    filter: alpha(opacity=80);
  }

  .jtk-endpoint {
    z-index: 21;
  }

  .jtk-endpoint:hover {
    cursor: pointer;
  }
</style>
